package ar.uba.fi.tonyvaliente.text.filtering;

import java.io.BufferedReader;
import java.io.File;
import java.io.FileNotFoundException;
import java.io.FileReader;
import java.io.IOException;
import java.util.ArrayList;
import java.util.HashMap;
import java.util.Iterator;
import java.util.LinkedList;

public class StopWordsFilter implements TextFilter {
	@Override
	public LinkedList<String> filter(LinkedList<String> text) {
		LinkedList<String> result = new LinkedList<String>();

		if (stopWords == null)
			populateStopWords();

		LinkedList<String> queue = new LinkedList<String>();
		for (String s : text) {
			queue.add(s);
			if (queue.size() == getMaxWordSequence()) {
				int sizeBefore = queue.size();
				filterQueue(queue);
				int sizeAfter = queue.size();
				if (sizeBefore == sizeAfter) {
					result.add(queue.removeFirst());
				}
			}
		}

		if (queue.size() > 0) {
			filterQueue(queue);
			while (queue.size() > 0) {
				result.add(queue.removeFirst());
			}
		}

		return result;
	}

	private static int maxWordSequence = 1;

	private static int getMaxWordSequence() {
		return maxWordSequence;
	}

	private static LinkedList<StopWord> stopWords = null;
	private static HashMap<Integer, LinkedList<StopWord>> stopWordsByLength = new HashMap<Integer, LinkedList<StopWord>>();
	private static HashMap<StopWordType, LinkedList<StopWord>> stopWordsByType = new HashMap<StopWordType, LinkedList<StopWord>>();
	private static LinkedList<String> adverbs = new LinkedList<String>();

	private static void filterQueue(LinkedList<String> queue) {
		ArrayList<String> list = new ArrayList<String>(queue);

		for (int i = getMaxWordSequence(); i > 0; i--) {
			if (i > queue.size())
				continue;

			LinkedList<StopWord> stopWords = stopWordsByLength.get(new Integer(
					i));
			for (StopWord stopWord : stopWords) {
				String[] value = stopWord.getValue();

				boolean found = true;
				for (int j = 0; j < list.size() && j < value.length; j++) {
					found = found && list.get(j).equals(value[j]);
					if (!found)
						break;
				}
				if (found) {
					for (int j = 0; j < i; j++)
						queue.removeFirst();
					return;
				}
			}
		}

		String word = list.get(0);
		if (isAdverb(word)) {
			queue.removeFirst();
		}
	}

	private static boolean isAdverb(String word) {
		if (word.endsWith("mente"))
			return true;

		if (adverbs.contains(word))
			return true;
		word = word.substring(0, word.length() - 1);
		if (adverbs.contains(word + "oto"))
			return true;
		if (adverbs.contains(word + "ita"))
			return true;
		if (adverbs.contains(word + "isimo"))
			return true;
		if (adverbs.contains(word + "isima"))
			return true;

		return false;
	}

	private static void populateStopWords() {
		stopWords = new LinkedList<StopWord>();

		File file = new File("settings/stop_words.txt");
		BufferedReader reader;
		try {
			reader = new BufferedReader(new FileReader(file));
		} catch (FileNotFoundException e) {
			e.printStackTrace();
			return;
		}

		LinkedList<TextFilter> filters = new LinkedList<TextFilter>();
		filters.add(new TermsFilter());
		filters.add(new CaseFoldingFilter());
		filters.add(new AcutesFilter());

		StopWordsFilter foo = new StopWordsFilter();

		try {
			String line;
			while ((line = reader.readLine()) != null) {
				line = line.trim();
				if (line.equals(""))
					continue;
				if (line.startsWith("#"))
					continue;

				int pos = line.indexOf(':');
				if (pos == -1)
					pos = line.length();
				String word = line.substring(0, pos);
				LinkedList<String> words = new LinkedList<String>();
				words.add(word);
				for (TextFilter filter : filters) {
					words = filter.filter(words);
				}
				String[] value = new String[words.size()];
				int i = 0;
				for (Iterator<String> it = words.iterator(); it.hasNext();)
					value[i++] = it.next();

				StopWordType type = StopWordType.Unknown;
				if (line.endsWith(":adberv"))
					type = StopWordType.Adverb;

				StopWord stopWord = foo.new StopWord(value, type);
				stopWords.add(stopWord);

				if (value.length > maxWordSequence)
					maxWordSequence = value.length;

				Integer lengthKey = new Integer(value.length);
				if (!stopWordsByLength.containsKey(lengthKey))
					stopWordsByLength
							.put(lengthKey, new LinkedList<StopWord>());
				stopWordsByLength.get(lengthKey).add(stopWord);

				StopWordType typeKey = type;
				if (!stopWordsByType.containsKey(typeKey))
					stopWordsByType.put(typeKey, new LinkedList<StopWord>());
				stopWordsByType.get(typeKey).add(stopWord);

				if (type == StopWordType.Adverb) {
					adverbs.add(word);
				}
			}
		} catch (IOException e) {
			e.printStackTrace();
		}
	}

	public class StopWord {
		private String[] value;
		private StopWordType type;

		public StopWord(String[] value, StopWordType type) {
			this.value = value;
			this.type = type;
		}

		public String[] getValue() {
			return this.value;
		}

		public StopWordType getType() {
			return this.type;
		}
	}

	public enum StopWordType {
		Unknown, Adverb
	}
}
